﻿/**
 * @file opus_encoder_test.cpp
 * Copyright (c) Gaaagaa. All rights reserved.
 * 
 * @author  : Gaaagaa
 * @date    : 2020-03-09
 * @version : 1.0.0.0
 * @brief   : PCM 音频数据编码（测试 opus_encoder_t）。
 */

#include "audio_opus.h"
#include "fwave_pcm.h"

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif // _MSC_VER

#include <vector>
#include <stdio.h>
#include <errno.h>

////////////////////////////////////////////////////////////////////////////////

#include "opus_fhelper.inl"

////////////////////////////////////////////////////////////////////////////////

int main(int argc, char * argv[])
{
    x_errno_t xerr_no = X_ERR_UNKNOW;
    x_int32_t xit_err = X_ERR_UNKNOW;

    //======================================

    if (argc < 3)
    {
        printf("Usage: \n\t %s < wave-pcm-s16 input file > < opus output file >\n", argv[0]);
        return -1;
    }

    //======================================

    fwave_rpcm_t fwave_rpcm;
    xerr_no = fwave_rpcm.open(argv[1]);
    if (XERR_FAILED(xerr_no))
    {
        printf("fwave_rpcm.open([%s]) return error code: %s\n",
               argv[1], fwave_rpcm_t::xerrno_name(xerr_no));
        return -1;
    }

    if (((1 != fwave_rpcm.format().xut_channels)  &&
         (2 != fwave_rpcm.format().xut_channels)) ||
        (16 != fwave_rpcm.format().xut_sampbits)  &&
        (32 != fwave_rpcm.format().xut_sampbits))
    {
        printf("pcm format: channels[%d] != [1, 2], sampbits[%d] != [16, 32]\n",
               fwave_rpcm.format().xut_channels, fwave_rpcm.format().xut_sampbits);
        return -1;
    }

    if (16 != fwave_rpcm.format().xut_sampbits)
    {
        printf("(16 != fwave_rpcm.format().xut_sampbits[%d])\n",
               fwave_rpcm.format().xut_sampbits);
        return -1;
    }

    //======================================

    x_uint32_t xut_config  = XOPUS_ENC_DEFAULT;
    x_uint32_t xut_bitrate = 0;

    opus_encoder_t opus_encoder;
    xerr_no = opus_encoder.open(
                    fwave_rpcm.format().xut_channels,
                    fwave_rpcm.format().xut_samprate,
                    xut_config,
                    xut_bitrate);
    if (X_ERR_OK != xerr_no)
    {
        printf("opus_encoder.open(%d, %d, ...) return error code: %d\n",
               fwave_rpcm.format().xut_channels,
               fwave_rpcm.format().xut_samprate,
               XERR_HINO(xerr_no));
        return -1;
    }

    //======================================

    FILE * fopus_writer = fopen(argv[2], "wb+");
    if (X_NULL == fopus_writer)
    {
        printf("fopen([%s], \"wb+\") return X_NULL, errno: %d\n", argv[2], errno);
        return -1;
    }

    x_uint32_t xut_ctxt = XOPUS_CTXT(
            fwave_rpcm.format().xut_channels,
            fwave_rpcm.format().xut_sampbits,
            fwave_rpcm.format().xut_samprate);
    if (0 == opus_whead(fopus_writer, xut_ctxt))
    {
        printf("opus_whead(..., xut_ctxt[%d]) return 0, errno: %d\n", xut_ctxt, errno);
        fclose(fopus_writer);
        return -1;
    }

    //======================================

    const x_uint32_t xut_maxlen = 2 * sizeof(x_int16_t) * XOPUS_SAMPRATE_48K;
    const x_uint32_t xut_frmlen = opus_encoder.frame_len();

    std::vector< x_byte_t > xvec_input (xut_maxlen, 0);
    std::vector< x_byte_t > xvec_output(xut_maxlen, 0);

    //======================================
    // AAC stream

    x_uint32_t xut_ibytes = 0;
    x_uint32_t xut_obytes = 0;

    while (X_TRUE)
    {
        //======================================

        if (xut_ibytes < xut_frmlen)
        {
            xut_ibytes += (x_uint32_t)fwave_rpcm.read(
                                        xvec_input.data() + xut_ibytes,
                                        (x_fsize_t)(xut_frmlen - xut_ibytes));
        }

        if (0 == xut_ibytes)
            break;

        if (xut_ibytes < xut_frmlen)
        {
            memset(xvec_input.data() + xut_ibytes, 0, xut_frmlen - xut_ibytes);
            xut_ibytes = xut_frmlen;
        }

        //======================================

        xut_obytes = (x_uint32_t)xvec_output.size();
        xerr_no = opus_encoder.encode(xvec_output.data(), xut_obytes,
                                      xvec_input.data(), xut_ibytes);
        if (XERR_FAILED(xerr_no))
        {
            printf("opus_encoder.encode(, %d, ) return error code: %s\n",
                    xut_obytes,
                    opus_encoder_t::xerrno_name(xerr_no));
            break;
        }

        //======================================

        printf("opus stream: input[%d], output[%d], frame_len[%d]\n",
               xut_ibytes, xut_obytes, xut_frmlen);

        if (xut_ibytes < xut_frmlen)
        {
            memmove(
                xvec_input.data(),
                xvec_input.data() + xut_ibytes,
                xut_frmlen - xut_ibytes);
            xut_ibytes = xut_frmlen - xut_ibytes;
        }
        else
        {
            xut_ibytes = 0;
        }

        //======================================

        if (xut_obytes <= 0)
        {
            continue;
        }

        opus_wframe(fopus_writer, xvec_output.data(), xut_obytes);

        //======================================
    }

    //======================================

    if (X_NULL != fopus_writer)
    {
        fclose(fopus_writer);
        fopus_writer = X_NULL;
    }

    fwave_rpcm.close();
    opus_encoder.close();

    //======================================

    return 0;
}
